GYP is the abbreviation for Generate Your Projects. The purpose of GYP is to support larger projects compiled on different platforms, such as Mac, Windows, and Linux. It can generate Xcode projects, Visual Studio projects, Ninja compiled files and Makefiles.
The input of GYP is .gyp and .gypi files. .gypi files are used for .gyp files to include. A .gyp file is a json file that conforms to a specific format.
First let’s look at a reduced .gyp file in Chromium:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
{ "variables": { ... }, "includes": [ "../build/common.gypi", ], "target_defaults": { ... }, "targets": [ { "target_name": "target_1", ... }, { "target_name": "target_2", ... }, ], "conditions": [ ["OS==\"linux\"", { "targets": [ { "target_name": "linux_target_3", ... }, ], }], ["OS==\"win\"", { "targets": [ { "target_name": "windows_target_4", ... }, ], }, { "targets": [ { "target_name": "non_windows_target_5", ... }, }], ], }
The values of the following properties are specified above:
variables: Define variables that may be modified or used elsewhere in the file.
includes: Need to include files with a .gypi suffix.
target_defaults: The default settings apply to all targets in the file.
targets: Specifies the list of targets generated by this file.
conditions: Specify different conditions and modify variables in the file.
Let’s check an example of building a simple executable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
{ "targets": [ { "target_name": "foo", "type": "executable", "msvs_guid": "5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65", "dependencies": [ "xyzzy", "../bar/bar.gyp:bar", ... ], "defines": [ "DEFINE_FOO", "DEFINE_A_VALUE=value", ... ], "include_dirs": [ ... ], "sources": [ "file1.cc", "file2.cc", ... ], "conditions": [ ["OS==\"linux\"", { "defines": [ "LINUX_DEFINE", ], "include_dirs": [ "include/linux", ], ... }], ["OS==\"win\"", { "defines": [ "WINDOWS_SPECIFIC_DEFINE", ], ... }, { "defines": [ "NON_WINDOWS_DEFINE", ... ], ... }] ], ... }, ... ], ... }
Where,
target_name: unique to represent the project name.
type: the file type, here is an executable.
msvs_guid: the GUID value used to generate the Visual Studio solution file.
dependencies: other targets that this target depends on.
defines: macro definition for -D or /D.
include_dirs: a folder containing header files for -I or /I.
sources: list of source files for this target.
conditions: some condition settings.
Finally let’s check an example of building a simple library:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
{ "targets": [ { "target_name": "foo", "type": "<(library)" "msvs_guid": "5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65", "dependencies": [ "xyzzy", "../bar/bar.gyp:bar", ... ], "defines": [ "DEFINE_FOO", "DEFINE_A_VALUE=value", ], "include_dirs": [ ... ], "direct_dependent_settings": { "defines": [ "DEFINE_FOO", "DEFINE_ADDITIONAL", ], "linkflags": [ ... ], ... }, "export_dependent_settings": [ "../bar/bar.gyp:bar", ... ], "sources": [ "file1.cc", "file2.cc", ... ], "conditions": [ ["OS==\"linux\"", { "defines": [ "LINUX_DEFINE", ], "include_dirs": [ "include/linux", ], ... ], ["OS==\"win\"", { "defines": [ "WINDOWS_SPECIFIC_DEFINE", ], ... }, { "defines": [ "NON_WINDOWS_DEFINE", ... ], }] ], ... ], ... }
You can see in the .gyp file for building a library, most of the JSON structures are the same as the executable, just a few are different:
type: type should be set to <(library)
direct_dependent_settings: These settings will be applied to targets that directly depend on this target, that is, the target is specified in dependencies.
export_dependent_settings: export the direct_dependent_settings of the column target to the target.
Let’s look at a few examples:
Generate an executable file foo. The source files involved in the compilation are independent.cc, specific_win.cc. You can specify a file on the specified platform to be involved in the compilation by specifying the suffixes _linux, _mac, _posix, and _win, For example, the specific_win.cc will be involved in compilation only on Windows platforms.
Here is the sample .gyp file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
{ "targets": [ { "target_name": "foo", "type": "executable", "sources": [ "independent.cc", "specific_win.cc", ], ... }, ... ], ... }, ... }
You can also specify conditions and add different conditions on different platforms as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
{ "targets": [ { "target_name": "foo", "type": "executable", "sources": [ "linux_specific.cc" ], "conditions": [ ["OS != " linux "", { "sources!": [ # Linux - only;exclude on other platforms. "linux_specific.cc", ] }, ... ], ... }, ... ], ... }
The above file indicates that if it is not a Linux platform, the source file linux_specific.cc is not included in the compilation.
Let’s look at the usage of dependencies:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
{ "targets": [ { "target_name": "new_unit_tests", "type": "executable", "defines": [ "FOO", ... ], "include_dirs": [ ... "include", ... ], "dependencies": [ "other_target_in_this_file", "other_gyp2:target_in_other_gyp2", ... ], "sources": [ "new_additional_source.cc", "new_unit_tests.cc", ... ], ... }, ... ], ... }
In the dependencies field, you can specify the dependency file, other targets for the dependency file, or a target for other files.
You can also specify compilation parameters (e.g., -Werror) like below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
{ "targets": [ { "target_name": "existing_target", "conditions": [ ["OS==\"win\"", { "cflags": [ "/WX", ], ... }, { # OS != "win" "cflags": [ "-Werror", ], ... }], ... ], ... }, ... ], ... }
The targets can also be inter-dependent between each other as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
{ "targets": [ { "target_name": "foo", "type": "executable", "dependencies": [ "libbar", ... ], ... }, { "target_name": "libbar", "type": "<(library)", "defines": [ "LOCAL_DEFINE_FOR_LIBBAR", "DEFINE_TO_USE_LIBBAR", ], "include_dirs": [ ... "include/libbar", ... ], "direct_dependent_settings": { "defines": [ "DEFINE_TO_USE_LIBBAR", ... ], "include_dirs": [ "include/libbar", ... ], }, ... }, ... ], ... }
In the above example, foo depends on libbar. If it is the libbar of other files, then it should be written as …/bar/bar.gyp:libbar.
And foo will add the compilation option -DDEFINE_TO_USE_LIBBAR -Iinclude /libbar.
You can also build Mac OS X bundles by GYP, here is an example,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"target_name": "test_app",
"product_name": "Test App Gyp",
"type": "executable",
"mac_bundle": 1,
"sources": [
"main.m",
"TestAppAppDelegate.h",
"TestAppAppDelegate.m"
],
"mac_bundle_resources": [
"TestApp/English.lproj/InfoPlist.strings",
"TestApp/English.lproj/MainMenu.xib"
],
"link_settings": {
"libraries": [
"$(SDKROOT)/System/Library/Frameworks/Cocoa.framework"
]
},
"xcode_settings": {
"INFOPLIST_FILE": "TestApp/TestApp-Info.plist"
},
...
}
GYP is a useful tool to build and manage large scale C/C++ projects, which are supposed to run on different platforms. GYP has more advantages than the conventional Makefile/automake tools. It was massively used by Google Chromium project.
We can also use it to manage our own C/C++ projects.
GYP is also evolving. In the next article, I’ll introduce its next generation build tool - GN.